#ifndef STREAM_H_INCLUDED
#define STREAM_H_INCLUDED

#include <string>
#include <fstream>
#include <map>

#include "types.h"
#include "records.h"

using namespace std;

namespace stdf {

/// \brief STDF Record Stream class
///
/// This class concerns itself primarily with raw binary cross-platform
/// file io and does not do too much of STDF format error checking.
/// Has the following features
/// * byte order translation details
/// * Basic types IO
/// * STDF Record Types IO
/// * File system handling and error handling
class Stream {
    public:
        // Construction/Destruction
        Stream();
        Stream(string name, RWMode mode);
        virtual ~Stream();

        // Options
        void setByteOrder( ByteOrder order);

        // IO
        virtual bool open(string name, RWMode mode);
        virtual bool close();
        virtual int skip( U2 length);

        bool is_open(void) { return filestream.is_open(); }
        bool good(void)    { return filestream.good(); }
        bool eof(void)    { return filestream.eof(); }
        int peek(void) { return filestream.peek(); }

        int readRecordHeader(RecordHeader& rh);
        int readRecord(FARRecord& rec, const unsigned int len=0);
        int readRecord(ATRRecord& rec, const unsigned int len=0);
        int readRecord(MIRRecord& rec, const unsigned int len=0);
        int readRecord(SDRRecord& rec, const unsigned int len=0);
        int readRecord(PMRRecord& rec, const unsigned int len=0);
        int readRecord(PGRRecord& rec, const unsigned int len=0);
        int readRecord(PIRRecord& rec, const unsigned int len=0);
        int readRecord(PLRRecord& rec, const unsigned int len=0);
        int readRecord(PTRRecord& rec, const unsigned int len=0);
        int readRecord(PRRRecord& rec, const unsigned int len=0);
        int readRecord(TSRRecord& rec, const unsigned int len=0);
        int readRecord(WCRRecord& rec, const unsigned int len=0);
        int readRecord(WIRRecord& rec, const unsigned int len=0);
        int readRecord(WRRRecord& rec, const unsigned int len=0);
        int readRecord(HBRRecord& rec, const unsigned int len=0);
        int readRecord(SBRRecord& rec, const unsigned int len=0);
        int readRecord(PCRRecord& rec, const unsigned int len=0);
        int readRecord(MRRRecord& rec, const unsigned int len=0);

        //RecordHeader& getHeader();

        // IO for Records
        // Status checks performed after each IO operation
        Stream& operator<<(RecordHeader& rh);
        Stream& operator>>(RecordHeader& rh);
        Stream& operator<<(FARRecord& far);
        Stream& operator>>(FARRecord& far);
        Stream& operator<<(ATRRecord& atr);
        Stream& operator>>(ATRRecord& atr);
        Stream& operator<<(MIRRecord& mir);
        Stream& operator>>(MIRRecord& mir);

        unsigned int getRecordTypeCount(RecordType recType) { return recordTypeCount[recType]; }

    public:




    private:
        void init(void);
	void beginRecord(const unsigned int len);
	int  endRecord(void);

        int read(U1& val);
        int read(U2& val);
        int read(U4& val);
        int read(I2& val);
        int read(I4& val);
        int read(R4& val);
        int read(R8& val);
        int read(C1& val);
        int read(CN& val);
        int read(BN& val);
        int read(DN& val);
        int read(VN& val);

        int write(U1& val);
        int write(U2& val);
        int write(U4& val);
        int write(I2& val);
        int write(I4& val);
        int write(R4& val);
        int write(R8& val);
        int write(C1& val);
        int write(CN& val);
        int write(BN& val);
        int write(DN& val);
        int write(VN& val);

        // IO for primary types Write -> operator "<<" , Read -> operator ">>"
        // translation is done while Read only, PDPEndian is not supported
        // Write is in native format only for speed
        Stream& operator<<(U1& u1);
        Stream& operator>>(U1& u1);
        Stream& operator<<(U2& u2);
        Stream& operator>>(U2& u2);
        Stream& operator<<(U4& u4);
        Stream& operator>>(U4& u4);
        Stream& operator<<(I2& i2);
        Stream& operator>>(I2& i2);
        Stream& operator<<(I4& i4);
        Stream& operator>>(I4& i4);
        Stream& operator<<(R4& val);
        Stream& operator>>(R4& val);
        Stream& operator<<(R8& val);
        Stream& operator>>(R8& val);
        Stream& operator<<(C1& val);
        Stream& operator>>(C1& val);
        Stream& operator<<(CN& val);
        Stream& operator>>(CN& val);
        Stream& operator<<(BN& val);
        Stream& operator>>(BN& val);
        Stream& operator<<(DN& val);
        Stream& operator>>(DN& val);
        Stream& operator<<(VN& val);
        Stream& operator>>(VN& val);
    private:
        string                        streamName;
        RWMode                        rwMode;
        ByteOrder                     desiredByteOrder;
        ByteOrder                     nativeByteOrder;
        bool                          swap;
        fstream                       filestream;
        unsigned long long            byteCount;
        unsigned long long            recStartCount;
        unsigned int                  recReadLengthMax;
        unsigned int                  recReadCount;
        RecordHeader                  currRecordHeader;
        map<RecordType, unsigned int> recordTypeCount;
};

} // end namespace

#endif // STREAM_H_INCLUDED
